using System;
using System.Data;
using System.Text.RegularExpressions;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using System.Xml;
using System.Xml.XPath;

using Actions;
using Actions.Connectors;
using Actions.Security;

namespace Actions.Security
{
	/// <summary>
	/// Control all Security operations.
	/// </summary>
	public class SecurityAgent
	{
		private bool _enable = false;
		private string _databaseId = "";
		
		private string _username = "_login";
		private string _password = "_secret";
		private string _usecase = "usecase";
		
		private string _userSession = "actions_current_user";
		private string _defaultUsecase = "Start";

		private string _regExp = "^[a-zA-Z0-9]{6,64}$";		
		
		private User			_user;
		private Usecase			_currentUsecase;
		private Usecase			_requestedUsecase;
				
		public bool	enable {
			get 
			{
				return _enable;
			}
		}
		public User				currentUser
		{
			get
			{
				return _user;
			}
		}		
		public Usecase			currentUsecase
		{
			get
			{
				if(!enable) return _requestedUsecase;
				else return _currentUsecase;
			}
		}
		public Usecase			requestedUsecase
		{
			get
			{
				return _requestedUsecase;
			}
		}		
			
		public SecurityAgent()
		{
			try {
				_enable = Boolean.Parse(Manager.i.config.
					GetValueOf("//Configuration/SecurityAgent/@enable"));
			
				if(_enable) {
					_databaseId = Manager.i.config.
						GetValueOf("//Configuration/SecurityAgent/DatabaseID");
			
					_username = Manager.i.config.
						GetValueOf("//Configuration/SecurityAgent/Username");
					_password = Manager.i.config.
						GetValueOf("//Configuration/SecurityAgent/Password");
					_usecase = Manager.i.config.
						GetValueOf("//Configuration/SecurityAgent/Usecase");
		
					_userSession = Manager.i.config.
						GetValueOf("//Configuration/SecurityAgent/SessionName");
					_defaultUsecase = Manager.i.config.
						GetValueOf("//Configuration/SecurityAgent/DefaultUsecase");

					_regExp = Manager.i.config.
						GetValueOf("//Configuration/SecurityAgent/RegExp");		
				}
			} finally { 
				_user = getDefaultUser();			
				_currentUsecase = _user.defaultUsecase;
				_requestedUsecase = _user.defaultUsecase;
			}			
		}

		public void init(ref IConnector c)
		{
			//
			// Init each security object
			//
			if(_enable) initUser(ref c);			 			
			findUsecase(ref c);
		}		
		
		public void userLogOut(ref IConnector c)
		{
			if(_enable) {
				_user = getDefaultUser();
				c.setSessionParam(_userSession, _user);
			}
		}
		
		public string usecaseRule(string uc)
		{
		   string res = "";
		
		   if(uc.Length > 0) {
	          res += "<AccessRule usecase='" + uc + 
	             "' allow='" + _user.checkUsecase(new Usecase(uc)).ToString() + "'/>";
		   }
		   return res; 
		}
		
		public void log(ref IConnector c)
		{
			string p = Manager.i.db(_databaseId).esc(c.getLogParams());	
				
			Manager.i.db(_databaseId).
				query(string.Format("INSERT INTO _log SET tmark=NOW(), user='{0}', ip='{1}', usecase='{2}', params='{3}'", 
					_user.login, c.getRemoteAddress(), _currentUsecase.name, p));
		}
		
		//
		// private methods
		//
						
		private void initUser(ref IConnector c)
		{
			string username = c.getInputParam(_username);
			string password = c.getInputParam(_password);			
			
			User cUser = null;			
			bool inSession = false;
			
			if(username != null && password != null){
				try {
					username.Trim();
					password.Trim();
				} catch {
					username = "";
					password = "";
				};
			
				//
				// Initialize user 
				//
				if(username.Length > 0 && password.Length > 0 && Regex.IsMatch(username, _regExp) && Regex.IsMatch(password, _regExp)) {
					//
					// New password and username was entered
					//	
					cUser = new User(_databaseId, username, password);
				} else {					
					//
					// Check the session
					//				
					cUser = (User) c.getSessionParam(_userSession);
					inSession = true;
				}
			} else {
				//
				// Check the session
				//				
				cUser = (User) c.getSessionParam(_userSession);
				inSession = true;
			}

			if(cUser == null) {
				//
				// Set default values
				//
				cUser = getDefaultUser();
				inSession = false;				

			}					

			if(!inSession) {
				//
				// User not in session, must be stored
				//
				c.setSessionParam(_userSession, cUser);
			}				
			
			_user = cUser;	
		}
		
		private void findUsecase(ref IConnector c)
		{
			string usecase = c.getInputParam(_usecase);			

			if(usecase != null) {
				try {
					usecase.Trim();
				} catch {
					usecase = "";
				};

				if(usecase.Length > 0 && Regex.IsMatch(usecase, _regExp)) {			
					_requestedUsecase = new Usecase(usecase);
					if(_user.checkUsecase(_requestedUsecase)) {
						_currentUsecase = _requestedUsecase;
					} else {
						_currentUsecase = new Usecase("403");
					}
				} else {
					_currentUsecase = new Usecase("404");				
				}			
			} 						
		}
		
		private User getDefaultUser()
		{
			User r = new User();
			r.defaultUsecase = new Usecase(_defaultUsecase);
			
			return r;
		}				
	}
}
